home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume91
/
utilitys
/
ed3_1_1
/
part02
/
create.c
next >
Wrap
C/C++ Source or Header
|
1991-11-07
|
17KB
|
754 lines
/*
These are polygon creation funtions of ed3.
10-22-91 add create_globe
10-16-91 all polyhedra except the pentagonal dodec are now created WITH faces
10-13-91 create_poly() now checks to see if there is room in the undo buf
09-06-91 adapted to use coord instead of short
09-02-91 add create_rhombic()
08-20-91 add code to contruct icos, dodec from radius OR edge length
08-19-91 add create_poly
add g_radius, g_edge_length
add code to contruct tet, oct, and cube from radius OR edge length
08-15-91 chg normalize() to call find_center and find_radius
*/
#include "sysnogr.h"
#define METHOD 2
char *poly_name[7] =
{
"Tetrahedron",
"Octahedron",
"Cube",
"Icosahedron",
"Pentagonal Dodecahedron",
"Rhombic Dodecahedron",
"Cuboctahedron"
};
/* number of points for each polyhedron */
short poly_points[7] =
{
4, 6, 8, 12, 20, 14, 12
};
/* number of triangular faces for each polyhedron */
short poly_faces[7] =
{
/* 4, 8, 6, 20, 12, 12, 14 total facets */
4, 8, 0, 20, 0, 0, 8
};
/* number of non-triangluar face for each polyhedron */
short poly_polys[7] =
{
0, 0, 6, 0, 12, 12, 6
};
/* these 2 variables are used in every function in this module */
/* g_ means global */
long g_radius, g_edge_length;
void create_poly(which_poly)
int which_poly;
{
int go = 1, event;
int id;
long data = 100, dimen = 100;
char title[50];
strcpy(title, "Create ");
strcat(title, poly_name[which_poly]);
sys_window(34, 4, title);
sys_movecur(1,0);
sys_say_text("Dimension:");
sys_get_long(data, 1);
sys_movecur(1,1);
sys_say_text("Create: using this value as");
sys_movecur(1,2);
sys_say_text("the ");
sys_boolean("Edge Length", 2);
sys_say_text(" or ");
sys_boolean("Radius", 3);
sys_activate(1);
while (go)
{
event = sys_read_event(&id, &data);
switch (event)
{
case EV_CANCEL:
sys_close_window();
return;
break;
case EV_CHECKINT:
case EV_HITRETURN:
case EV_HITBUTTON:
if (id == 1)
{
if (data > 8000) data = 8000;
if (data < 5) data = 5;
dimen = data;
}
else if (id == 2)
{
g_edge_length = dimen;
g_radius = 0;
go = 0;
}
else if (id == 3)
{
g_edge_length = 0;
g_radius = dimen;
go = 0;
}
break;
}
}
sys_close_window();
if (!enough_room(poly_points[which_poly],
poly_faces[which_poly],
poly_polys[which_poly],
0, 0, 0, 0, 0))
{
/* this operation could overflow the undo buffer! */
if (!tell_user_overflow()) return;
}
begin_operation();
switch (which_poly)
{
case POLY_TET: create_tetra(1); break;
case POLY_OCT: create_octa(1); break;
case POLY_CUBE: create_cube(1); break;
case POLY_ICOS: create_icosa(1); break;
case POLY_DODEC: create_dodec(1); break;
case POLY_RHOMB: create_rhombic(1); break;
case POLY_CUBOCT: create_cuboct(1); break;
}
end_operation();
}
/* all polyhedra created are centered at the origin */
void create_tetra(connected)
int connected;
{
double edge, radius, height,
face_radius; /* radius of each triangular face */
coord top_z, base_z;
index f; /* index on the first point created */
if (g_edge_length)
{
edge = (double)g_edge_length;
radius = sqrt(3.)/(2.*sqrt(2.)) * edge;
height = sqrt(2./3.) * edge;
face_radius = 1./sqrt(3.) * edge; /* radius of each triangular face */
}
else
{
radius = (double)g_radius;
edge = 2.*sqrt(2./3.) * radius;
height = 4./(3.*sqrt(3.)) * radius;
face_radius = 2.*sqrt(2.)/3. * radius; /* radius of each triangular face */
}
top_z = (coord)(.75 * height);
base_z = (coord)(-.25 * height);
f = points;
add_point(zero, zero, top_z); /* top */
add_point((coord)(-edge/2.), (coord)(-face_radius/2.), base_z);
add_point((coord)( edge/2.), (coord)(-face_radius/2.), base_z);
add_point(zero, (coord)face_radius, base_z);
convert_points();
if (!connected) return;
add_face1(f, f+1, f+2);
add_face1(f, f+2, f+3);
add_face1(f, f+3, f+1);
add_face1(f+1, f+2, f+3);
}
void create_octa(connected)
int connected;
{
double edge, radius;
coord r;
int f;
if (g_radius)
{
radius = g_radius;
edge = sqrt(2.)*radius;
}
else
{
edge = g_edge_length;
radius = edge/sqrt(2.);
}
r = radius;
f = points;
add_point(zero, zero, r);
add_point(zero, zero, -r);
add_point(zero, r, zero);
add_point(zero, -r, zero);
add_point( r, zero, zero);
add_point(-r, zero, zero);
convert_points();
if (!connected) return;
add_face1(f, f+2, f+4);
add_face1(f, f+4, f+3);
add_face1(f, f+3, f+5);
add_face1(f, f+5, f+2);
add_face1(f+1, f+2, f+4);
add_face1(f+1, f+4, f+3);
add_face1(f+1, f+3, f+5);
add_face1(f+1, f+5, f+2);
}
void create_cube(connected)
int connected;
{
double edge, radius;
coord half;
index np[4]; /* new polygon */
index f;
if (g_radius)
{
radius = g_radius;
edge = radius*2./sqrt(3.);
}
else
{
edge = g_edge_length;
radius = edge*sqrt(3.)/2;
}
half = edge/2.;
f = points;
add_point( half, half, half);
add_point( half, half, -half);
add_point( half, -half, half);
add_point( half, -half, -half);
add_point(-half, half, half);
add_point(-half, half, -half);
add_point(-half, -half, half);
add_point(-half, -half, -half);
convert_points();
if (!connected) return;
np[0] = f; np[1] = f+1; np[2] = f+5; np[3] = f+4;
add_poly(4, colors.newface, np, 0);
np[0] = f; np[1] = f+2; np[2] = f+3; np[3] = f+1;
add_poly(4, colors.newface, np, 0);
np[0] = f; np[1] = f+4; np[2] = f+6; np[3] = f+2;
add_poly(4, colors.newface, np, 0);
np[0] = f+7; np[1] = f+5; np[2] = f+1; np[3] = f+3;
add_poly(4, colors.newface, np, 0);
np[0] = f+7; np[1] = f+6; np[2] = f+4; np[3] = f+5;
add_poly(4, colors.newface, np, 0);
np[0] = f+7; np[1] = f+3; np[2] = f+2; np[3] = f+6;
add_poly(4, colors.newface, np, 0);
}
void create_icosa(connected)
int connected;
{
double edge, radius;
index f;
#ifdef METHOD1
double deg_x = 37. + (22./60.) + (38.527/3600.), /* deg, min, sec. */
deg_phi = 31. + (43./60.) + (2.907/3600.),
deg_3 = 20. + (54./60.) + (18.566/3600.);
double r_x = deg_x * PI / 180., /* convert to radians */
r_phi = deg_phi * PI / 180.,
r_3 = deg_3 * PI / 180.;
double phi, theta;
index i;
coord x, y, z;
#else
double tau;
coord tau2, edg2;
#endif
if (g_edge_length)
{
edge = (double)g_edge_length;
radius = sqrt((5. + sqrt(5.0)) / 8.) * edge;
}
else
{
radius = (double)g_radius;
edge = sqrt(8. / (5. + sqrt(5.0))) * radius;
}
f = points;
#if METHOD == 1
add_point(zero, zero, (coord)radius); /* top point */
add_point(zero, zero, (coord)-radius); /* bottom point */
phi = 2. * r_phi; /* top pentagon , points 72deg apart */
for (i = 0; i < 5; i++)
{
theta = i * (.4 * PI);
x = radius * sin(phi) * cos(theta);
y = radius * sin(phi) * sin(theta);
z = radius * cos(phi);
add_point(x, y, z);
}
phi = 2.*r_x + 2.*r_3; /* bottom pentagon */
for (i = 0; i < 5; i++)
{
theta = i * (.4 * PI) + (.2*PI); /* offset by 36deg */
x = radius * sin(phi) * cos(theta);
y = radius * sin(phi) * sin(theta);
z = radius * cos(phi);
add_point(x, y, z);
}
#else
/*
The expression for the radius of an icosahedron with edge length 1 is
sqrt(t+2)/2, where t (usually called tau) is the golden mean
(1+sqrt(5))/2
The coordinates of the vertices of an icosahedon of edge length 2 are:
(1,0,t), (t,1,0), (0,t,1), (-1,0,t), (0,-t,1), (t,-1,0),
and reverse all of the signs for the other six vertices.
******************************************************************************
Byron D. Biggs bdb9u@virginia.{EDU,BITNET}
*/
tau = (1.0+sqrt(5.0))/2.0;
tau2 = (coord)(tau / 2.0 * edge); /* we divide by 2 for a unit edge */
edg2 = (coord)(edge / 2.0);
add_point( edg2, zero, tau2);
add_point( edg2, zero, -tau2);
add_point(-edg2, zero, tau2);
add_point(-edg2, zero, -tau2);
add_point( zero, tau2, edg2);
add_point( zero, tau2, -edg2);
add_point( zero, -tau2, edg2);
add_point( zero, -tau2, -edg2);
add_point( tau2, edg2, zero);
add_point( tau2, -edg2, zero);
add_point(-tau2, edg2, zero);
add_point(-tau2, -edg2, zero);
#endif
convert_points();
if (!connected) return;
add_face1(f+5, f+1, f+3);
add_face1(f+5, f+8, f+1);
add_face1(f+5, f+4, f+8);
add_face1(f+5, f+10, f+4);
add_face1(f+5, f+3, f+10);
add_face1(f+10, f+3, f+11);
add_face1(f+3, f+7, f+11);
add_face1(f+3, f+1, f+7);
add_face1(f+1, f+9, f+7);
add_face1(f+1, f+8, f+9);
add_face1(f+8, f+0, f+9);
add_face1(f+8, f+4, f+0);
add_face1(f+4, f+2, f+0);
add_face1(f+4, f+10, f+2);
add_face1(f+10, f+11, f+2);
add_face1(f+2, f+11, f+6);
add_face1(f+11, f+7, f+6);
add_face1(f+7, f+9, f+6);
add_face1(f+9, f+0, f+6);
add_face1(f+0, f+2, f+6);
}
void create_dodec(connected)
int connected;
{
double gold = (sqrt(5.)+1)/2.,
igold = 1./gold;
double edge, radius;
coord e, g, i;
index np[5]; /* new polygon */
if (g_radius)
{
radius = g_radius;
edge = radius/sqrt(3.);
}
else
{
edge = g_edge_length;
radius = edge*sqrt(3.);
}
gold *= edge;
igold *= edge;
e = (coord)edge;
g = (coord)gold;
i = (coord)igold;
add_point(zero, i, g);
add_point(zero, -i, g);
add_point(zero, i, -g);
add_point(zero, -i, -g);
add_point( g, zero, i);
add_point( g, zero, -i);
add_point(-g, zero, i);
add_point(-g, zero, -i);
add_point( i, g, zero);
add_point(-i, g, zero);
add_point( i, -g, zero);
add_point(-i, -g, zero);
/* this method of constructing a dodecahedron reveals an
inscribed cube */
add_point( e, e, e);
add_point( e, e, -e);
add_point( e, -e, e);
add_point( e, -e, -e);
add_point( -e, e, e);
add_point( -e, e, -e);
add_point( -e, -e, e);
add_point( -e, -e, -e);
convert_points();
if (!connected) return;
}
void create_rhombic(connected)
int connected;
{
double edge, radius;
double half; /* inner radius */
coord ra, ha;
index f;
index np[4]; /* new polygon */
if (g_radius)
{
radius = g_radius;
edge = radius / (2.0 * sqrt(3.));
}
else
{
edge = g_edge_length;
radius = edge * 2.0 / sqrt(3.);
}
half = 0.5 * radius; /* inner radius */
ra = radius;
ha = half;
f = points;
add_point(zero, zero, ra);
add_point(zero, zero, -ra);
add_point(zero, ra, zero);
add_point(zero, -ra, zero);
add_point( ra, zero, zero);
add_point(-ra, zero, zero);
add_point(-ha, -ha, -ha);
add_point(-ha, -ha, ha);
add_point(-ha, ha, -ha);
add_point(-ha, ha, ha);
add_point( ha, -ha, -ha);
add_point( ha, -ha, ha);
add_point( ha, ha, -ha);
add_point( ha, ha, ha);
convert_points();
if (!connected) return;
np[0] = f+8; np[1] = f+2; np[2] = f+12; np[3] = f+1;
add_poly(4, colors.newface, np, 0);
np[0] = f+12; np[1] = f+2; np[2] = f+13; np[3] = f+4;
add_poly(4, colors.newface, np, 0);
np[0] = f+13; np[1] = f+2; np[2] = f+9; np[3] = f+0;
add_poly(4, colors.newface, np, 0);
np[0] = f+9; np[1] = f+2; np[2] = f+8; np[3] = f+5;
add_poly(4, colors.newface, np, 0);
np[0] = f+6; np[1] = f+1; np[2] = f+10; np[3] = f+3;
add_poly(4, colors.newface, np, 0);
np[0] = f+10; np[1] = f+4; np[2] = f+11; np[3] = f+3;
add_poly(4, colors.newface, np, 0);
np[0] = f+11; np[1] = f+0; np[2] = f+7; np[3] = f+3;
add_poly(4, colors.newface, np, 0);
np[0] = f+7; np[1] = f+5; np[2] = f+6; np[3] = f+3;
add_poly(4, colors.newface, np, 0);
np[0] = f+12; np[1] = f+4; np[2] = f+10; np[3] = f+1;
add_poly(4, colors.newface, np, 0);
np[0] = f+13; np[1] = f+0; np[2] = f+11; np[3] = f+4;
add_poly(4, colors.newface, np, 0);
np[0] = f+9; np[1] = f+5; np[2] = f+7; np[3] = f+0;
add_poly(4, colors.newface, np, 0);
np[0] = f+8; np[1] = f+1; np[2] = f+6; np[3] = f+5;
add_poly(4, colors.newface, np, 0);
}
void create_cuboct(connected)
int connected;
{
double edge; /* note: radius = edge length */
double in;
index i, j, k;
coord e;
index np[4]; /* new polygon */
index f;
edge = g_edge_length;
/* e is half the edge length of the surounding cube, whose edge is
sqrt(2) * edge of the cuboct */
/* (distance from the cuboct's center to the middle of a square edge) */
in = edge/sqrt(2.);
e = (coord)in;
f = points;
for (i = -1; i <= 1; i++)
for (j = -1; j <= 1; j++)
for (k = -1; k <= 1; k++)
if ((i&&j&&!k) || (i&&!j&&k) || (!i&&j&&k))
add_point(i*e, j*e, k*e);
convert_points();
if (!connected) return;
np[0] = f+1; np[1] = f+6; np[2] = f+9; np[3] = f+4;
add_poly(4, colors.newface, np, 0);
np[0] = f+9; np[1] = f+11; np[2] = f+10; np[3] = f+8;
add_poly(4, colors.newface, np, 0);
np[0] = f+10; np[1] = f+7; np[2] = f+2; np[3] = f+5;
add_poly(4, colors.newface, np, 0);
np[0] = f+2; np[1] = f+3; np[2] = f+1; np[3] = f+0;
add_poly(4, colors.newface, np, 0);
np[0] = f+7; np[1] = f+11; np[2] = f+6; np[3] = f+3;
add_poly(4, colors.newface, np, 0);
np[0] = f+0; np[1] = f+4; np[2] = f+8; np[3] = f+5;
add_poly(4, colors.newface, np, 0);
add_face1(6, 11, 9);
add_face1(11, 7, 10);
add_face1(7, 3, 2);
add_face1(3, 6, 1);
add_face1(9, 8, 4);
add_face1(10, 5, 8);
add_face1(2, 0, 5);
add_face1(1, 4, 0);
}
void create_globe()
{
long radius = 100, phi_div = 4, theta_div = 8;
int go = 1, event;
int id;
long data;
int add_p, add_f, add_q;
sys_window(34, 6, "Create Globe");
sys_movecur(1,0);
sys_say_text("Radius:");
sys_get_long(radius, 1);
sys_movecur(1,1);
sys_say_text("Divisions in phi:");
sys_get_long(phi_div, 2);
sys_movecur(1,2);
sys_say_text("Divisions in theta:");
sys_get_long(theta_div, 3);
sys_movecur(3,4);
sys_boolean(" OK ", 4);
sys_movecur(15,4);
sys_boolean("Cancel", 5);
sys_activate(1);
while (go)
{
event = sys_read_event(&id, &data);
switch (event)
{
case EV_CANCEL:
sys_close_window();
return;
break;
case EV_CHECKINT:
case EV_HITRETURN:
if (id == 1)
{
if (data > 8000) data = 8000;
if (data < 5) data = 5;
radius = data;
if (event == EV_HITRETURN) sys_activate(2);
}
else if (id == 2)
{
if (data > 100) data = 100;
if (data < 2) data = 2;
phi_div = data;
if (event == EV_HITRETURN) sys_activate(3);
}
else if (id == 3)
{
if (data > 100) data = 100;
if (data < 2) data = 2;
theta_div = data;
if (event == EV_HITRETURN) go = 0;
}
break;
case EV_HITBUTTON:
if (id == 4) go = 0;
}
}
sys_close_window();
/* calculate the number of points, faces and quads that will be created */
add_p = 2 + ((phi_div - 1) * theta_div);
add_f = 2 * theta_div;
add_q = (phi_div - 2) * theta_div;
if (!enough_room(add_p, add_f, add_q, 0, 0, 0, 0, 4))
{
/* this operation could overflow the undo buffer! */
if (!tell_user_overflow()) return;
}
begin_operation();
create_globe0((coord)radius, phi_div, theta_div);
end_operation();
}
void create_globe0(radius, phi_div, theta_div)
coord radius;
int phi_div, theta_div;
{
index p0, p1;
index base, line_start;
int phi, theta;
double d_phi, d_theta;
coord x, y, z;
index np[4]; /* new polygon */
/* add the pole points */
p0 = points;
add_point(zero, radius, zero);
p1 = points;
add_point(zero, -radius, zero);
base = points;
d_phi = (PI / phi_div);
for (phi = 1; phi < phi_div; phi++)
{
d_theta = 0.0;
for (theta = 0; theta < theta_div; theta++)
{
x = cos(d_theta) * sin(d_phi) * radius;
z = sin(d_theta) * sin(d_phi) * radius;
y = cos(d_phi) * radius;
/* note that y and z are swapped, our coordinates are LEFT-handed */
add_point(x, y, z);
d_theta += (2.0 * PI / theta_div);
}
d_phi += (PI / phi_div);
}
/* add top triangles */
for (theta = 0; theta < theta_div; theta++)
add_face1(p0, base + theta, base + ((theta+1)%theta_div));
/* add center quads (if any) */
if (phi_div > 2)
{
for (phi = 0; phi < (phi_div-2); phi++)
{
line_start = base + (phi*theta_div);
for (theta = 0; theta < theta_div; theta++)
{
np[0] = line_start + theta;
np[1] = line_start + (theta+1)%theta_div;
np[2] = np[1] + theta_div;
np[3] = np[0] + theta_div;
add_poly(4, colors.newface, np, 0);
}
}
}
/* add bottom triangles */
line_start = base + ((phi_div - 2) * theta_div);
for (theta = 0; theta < theta_div; theta++)
add_face1(p1, line_start + theta, line_start + ((theta+1)%theta_div));
}
void normalize() /* set all points equidistant from their center */
{
uindex i;
double cx, cy, cz, radius, d2, scale_factor;
coord dx, dy, dz;
/* to find the center of the object, we average the location of
the points */
begin_operation();
find_center(&cx, &cy, &cz);
find_radius(cx, cy, cz, &radius);
#if 0
printf("center %f %f %f radius %f\n", cx, cy, cz, radius);
#endif
for (i = 0; i < points; i++)
{
dx = point[i].x - cx;
dy = point[i].y - cy;
dz = point[i].z - cz;
d2 = sqrt((double)(dx*dx + dy*dy + dz*dz));
scale_factor = radius / d2;
point[i].x = cx + (dx * scale_factor);
point[i].y = cy + (dy * scale_factor);
point[i].z = cz + (dz * scale_factor);
convert_point(i);
}
end_operation();
}